package windows;

import game.Game;
import game.GameResults;
import game.GameSettings;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedList;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingWorker;
import javax.swing.border.TitledBorder;

public class MainFrame extends JFrame implements PropertyChangeListener {
	public class Task extends SwingWorker<Void, Void> {
		public boolean interrupted;
		public Task(){
			super();
			interrupted = false;
		}
		public Void doInBackground() {
			simulation();
			return null;
		}
		public void setProgressIn(int prog){
			setProgress(Math.min(prog, 100));//metoda pozwalajaca na dostep do prywatnej metody setprogress
		}

		public void simulation() {
			LinkedList<GameResults> results = new LinkedList<>();
			for(int i=0;i<GameSettings.roundsToSimulate;i++) {
				Game game = new Game(GameSettings.playerCount, GameSettings.deckCount);
				results.add(game.startGame());
				setProgressIn((int)(100.0*(double)i/(double)GameSettings.roundsToSimulate));
				if(interrupted) {
					setProgressIn(0);
					return;
				}
			}
			
			int nodraws=0;
			long battles=0;
			long wars=0;
			int lbattles=1000000;
			int mbattles=0;
			int lwars=1000000;
			int mwars=0;
			int rulesDraws = 0;
			int loopDraws = 0;
			for(GameResults result: results) {
				if(result.drawByInfiniteGameLoop) {
					loopDraws++;
					continue;
				}
				if(result.drawByRules) {
					rulesDraws++;
					continue;
				}
				nodraws++;
				battles+=result.battles;
				wars+=result.wars;
				if(result.battles<lbattles)
					lbattles=result.battles;
				if(result.battles>mbattles)
					mbattles=result.battles;
				if(result.wars<lwars)
					lwars=result.wars;
				if(result.wars>mwars)
					mwars=result.wars;
			}
			String endString =("Rounds simulated: "+results.size()+" Draws: "+(rulesDraws+loopDraws)+"("+rulesDraws+" by rules, "+loopDraws+" by infinite loop)\n");
			endString+=("BATTLES {min "+lbattles+", avg "+((double)battles/(double)nodraws)+", max "+mbattles+"}\n");
			endString+=("WARS {min "+lwars+", avg "+((double)wars/(double)nodraws)+", max "+mwars+"}");
			JOptionPane.showMessageDialog(MainFrame.this, endString , "End of simulation!", JOptionPane.PLAIN_MESSAGE);
		}
		
		public void done() {//wykonane po wygenerowaniu krzyzowki
			if(interrupted)
				return;
			Toolkit.getDefaultToolkit().beep();
			MainFrame.this.TaskDone();
			repaint();
		}
	}
	
	private JPanel mainPanel;
	
	private JPanel controlPanel;
	private JSpinner playerCountSpinner;
	private JLabel playerCountLabel;
	private JSpinner deckCountSpinner;
	private JLabel deckCountLabel;
	private JSpinner jkrPerDeckSpinner;
	private JLabel jkrPerDeckLabel;
	private JSpinner roundCountSpinner;
	private JLabel roundCountLabel;
	private JSpinner maxIterSpinner;
	private JLabel maxIterLabel;
	private JCheckBox miniDeckTick;
	private JProgressBar progressBar;
	
	private JPanel buttonPanel;
	private JButton startButton;
	private JButton stopButton;
	private JButton exitButton;
	
	private MainFrame.Task task;
	
	public MainFrame() {
		super();
		setTitle("War simulation v1.01");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
		createMainPanel();
		setContentPane(mainPanel);
		setMinimumSize(new Dimension(260, 160));
		setMaximumSize(new Dimension(260, 160));
		pack();
	}

	private void createMainPanel() {
		mainPanel=new JPanel();
		mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
		createControlPanel();
		mainPanel.add(controlPanel);
		createButtonPanel();
		mainPanel.add(buttonPanel);
	}
	
	private void createButtonPanel() {
		buttonPanel = new JPanel();
		startButton = new JButton("Start");
		startButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				startClicked();
			}
		});
		buttonPanel.add(startButton);
		stopButton  = new JButton("Stop");
		stopButton.setEnabled(false);
		stopButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				stopClicked();
			}
		});
		buttonPanel.add(stopButton);
		exitButton = new JButton("Exit");
		exitButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				exitClicked();
			}
		});
		buttonPanel.add(exitButton);
	}
	
	private void createControlPanel() {
		controlPanel = new JPanel();
		controlPanel.setBorder(new TitledBorder("Options"));
		//controlPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
		
		playerCountLabel = new JLabel("Players");
		playerCountSpinner = new JSpinner(new SpinnerNumberModel(2, 1, 10, 1));
		playerCountLabel.setLabelFor(playerCountSpinner);
		controlPanel.add(playerCountLabel);
		controlPanel.add(playerCountSpinner);
		
		deckCountLabel = new JLabel("Card decks");
		deckCountSpinner = new JSpinner(new SpinnerNumberModel(2, 1, 20, 1));
		deckCountLabel.setLabelFor(deckCountSpinner);
		controlPanel.add(deckCountLabel);
		controlPanel.add(deckCountSpinner);
		
		jkrPerDeckLabel = new JLabel("Joker/deck");
		jkrPerDeckSpinner = new JSpinner(new SpinnerNumberModel(3, 0, 10, 1));
		jkrPerDeckLabel.setLabelFor(jkrPerDeckSpinner);
		controlPanel.add(jkrPerDeckLabel);
		controlPanel.add(jkrPerDeckSpinner);
		
		roundCountLabel = new JLabel("Rounds to simulate");
		roundCountSpinner = new JSpinner(new SpinnerNumberModel(1000, 1, 1000000, 1));
		roundCountLabel.setLabelFor(roundCountSpinner);
		controlPanel.add(roundCountLabel);
		controlPanel.add(roundCountSpinner);
		
		maxIterLabel = new JLabel("Max iterations");
		maxIterSpinner = new JSpinner(new SpinnerNumberModel(250000, 1, 10000000, 1));
		maxIterLabel.setLabelFor(maxIterSpinner);
		controlPanel.add(maxIterLabel);
		controlPanel.add(maxIterSpinner);
		
		miniDeckTick = new JCheckBox("Use 9-A decks");
		controlPanel.add(miniDeckTick);
		
		progressBar=new JProgressBar(0,100);
		progressBar.setStringPainted(true);
		progressBar.setValue(0);
		progressBar.setAlignmentX(LEFT_ALIGNMENT);
		controlPanel.add(progressBar);
	}
	
	private void startClicked() {
		disableButtons();
		GameSettings.deckCount=(int)deckCountSpinner.getValue();
		GameSettings.jkrPerDeck=(int)jkrPerDeckSpinner.getValue();
		GameSettings.playerCount=(int)playerCountSpinner.getValue();
		GameSettings.roundsToSimulate=(int)roundCountSpinner.getValue();
		GameSettings.maxIterations=(int)maxIterSpinner.getValue();
		GameSettings.miniDecks=miniDeckTick.isSelected();
		progressBar.setValue(0);
		task = new Task();
		task.addPropertyChangeListener(this);
		task.execute();
	}
	
	private void stopClicked() {
		task.cancel(false);
		task.interrupted=true;
		task=null;
		progressBar.setValue(0);
	}

	private void exitClicked() {
		System.exit(0);
	}
	
	private void disableButtons() {
		playerCountSpinner.setEnabled(false);
		deckCountSpinner.setEnabled(false);
		jkrPerDeckSpinner.setEnabled(false);
		roundCountSpinner.setEnabled(false);
		maxIterSpinner.setEnabled(false);
		startButton.setEnabled(false);
		miniDeckTick.setEnabled(false);
		stopButton.setEnabled(true);
	}
	
	private void enableButtons() {
		playerCountSpinner.setEnabled(true);
		deckCountSpinner.setEnabled(true);
		jkrPerDeckSpinner.setEnabled(true);
		roundCountSpinner.setEnabled(true);
		maxIterSpinner.setEnabled(true);
		startButton.setEnabled(true);
		miniDeckTick.setEnabled(true);
		stopButton.setEnabled(false);
	}
	
	public void TaskDone() {
		progressBar.setValue(100);
		enableButtons();
	}

	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		if ("progress" == evt.getPropertyName()) {
			int progress = (Integer) evt.getNewValue();
			progressBar.setValue(progress);
		} 
		
	}
}
